package goquery

import (
	

	
)

// After applies the selector from the root document and inserts the matched elements
// after the elements in the set of matched elements.
//
// If one of the matched elements in the selection is not currently in the
// document, it's impossible to insert nodes after it, so it will be ignored.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( string) *Selection {
	return .AfterMatcher(compileMatcher())
}

// AfterMatcher applies the matcher from the root document and inserts the matched elements
// after the elements in the set of matched elements.
//
// If one of the matched elements in the selection is not currently in the
// document, it's impossible to insert nodes after it, so it will be ignored.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( Matcher) *Selection {
	return .AfterNodes(.MatchAll(.document.rootNode)...)
}

// AfterSelection inserts the elements in the selection after each element in the set of matched
// elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( *Selection) *Selection {
	return .AfterNodes(.Nodes...)
}

// AfterHtml parses the html and inserts it after the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( string) *Selection {
	return .eachNodeHtml(, true, func( *html.Node,  []*html.Node) {
		 := .NextSibling
		for ,  := range  {
			if .Parent != nil {
				.Parent.InsertBefore(, )
			}
		}
	})
}

// AfterNodes inserts the nodes after each element in the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( ...*html.Node) *Selection {
	return .manipulateNodes(, true, func( *html.Node,  *html.Node) {
		if .Parent != nil {
			.Parent.InsertBefore(, .NextSibling)
		}
	})
}

// Append appends the elements specified by the selector to the end of each element
// in the set of matched elements, following those rules:
//
// 1) The selector is applied to the root document.
//
// 2) Elements that are part of the document will be moved to the new location.
//
// 3) If there are multiple locations to append to, cloned nodes will be
// appended to all target locations except the last one, which will be moved
// as noted in (2).
func ( *Selection) ( string) *Selection {
	return .AppendMatcher(compileMatcher())
}

// AppendMatcher appends the elements specified by the matcher to the end of each element
// in the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( Matcher) *Selection {
	return .AppendNodes(.MatchAll(.document.rootNode)...)
}

// AppendSelection appends the elements in the selection to the end of each element
// in the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( *Selection) *Selection {
	return .AppendNodes(.Nodes...)
}

// AppendHtml parses the html and appends it to the set of matched elements.
func ( *Selection) ( string) *Selection {
	return .eachNodeHtml(, false, func( *html.Node,  []*html.Node) {
		for ,  := range  {
			.AppendChild()
		}
	})
}

// AppendNodes appends the specified nodes to each node in the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( ...*html.Node) *Selection {
	return .manipulateNodes(, false, func( *html.Node,  *html.Node) {
		.AppendChild()
	})
}

// Before inserts the matched elements before each element in the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( string) *Selection {
	return .BeforeMatcher(compileMatcher())
}

// BeforeMatcher inserts the matched elements before each element in the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( Matcher) *Selection {
	return .BeforeNodes(.MatchAll(.document.rootNode)...)
}

// BeforeSelection inserts the elements in the selection before each element in the set of matched
// elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( *Selection) *Selection {
	return .BeforeNodes(.Nodes...)
}

// BeforeHtml parses the html and inserts it before the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( string) *Selection {
	return .eachNodeHtml(, true, func( *html.Node,  []*html.Node) {
		for ,  := range  {
			if .Parent != nil {
				.Parent.InsertBefore(, )
			}
		}
	})
}

// BeforeNodes inserts the nodes before each element in the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( ...*html.Node) *Selection {
	return .manipulateNodes(, false, func( *html.Node,  *html.Node) {
		if .Parent != nil {
			.Parent.InsertBefore(, )
		}
	})
}

// Clone creates a deep copy of the set of matched nodes. The new nodes will not be
// attached to the document.
func ( *Selection) () *Selection {
	 := newEmptySelection(.document)
	.Nodes = cloneNodes(.Nodes)
	return 
}

// Empty removes all children nodes from the set of matched elements.
// It returns the children nodes in a new Selection.
func ( *Selection) () *Selection {
	var  []*html.Node

	for ,  := range .Nodes {
		for  := .FirstChild;  != nil;  = .FirstChild {
			.RemoveChild()
			 = append(, )
		}
	}

	return pushStack(, )
}

// Prepend prepends the elements specified by the selector to each element in
// the set of matched elements, following the same rules as Append.
func ( *Selection) ( string) *Selection {
	return .PrependMatcher(compileMatcher())
}

// PrependMatcher prepends the elements specified by the matcher to each
// element in the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( Matcher) *Selection {
	return .PrependNodes(.MatchAll(.document.rootNode)...)
}

// PrependSelection prepends the elements in the selection to each element in
// the set of matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( *Selection) *Selection {
	return .PrependNodes(.Nodes...)
}

// PrependHtml parses the html and prepends it to the set of matched elements.
func ( *Selection) ( string) *Selection {
	return .eachNodeHtml(, false, func( *html.Node,  []*html.Node) {
		 := .FirstChild
		for ,  := range  {
			.InsertBefore(, )
		}
	})
}

// PrependNodes prepends the specified nodes to each node in the set of
// matched elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( ...*html.Node) *Selection {
	return .manipulateNodes(, true, func( *html.Node,  *html.Node) {
		// sn.FirstChild may be nil, in which case this functions like
		// sn.AppendChild()
		.InsertBefore(, .FirstChild)
	})
}

// Remove removes the set of matched elements from the document.
// It returns the same selection, now consisting of nodes not in the document.
func ( *Selection) () *Selection {
	for ,  := range .Nodes {
		if .Parent != nil {
			.Parent.RemoveChild()
		}
	}

	return 
}

// RemoveFiltered removes from the current set of matched elements those that
// match the selector filter. It returns the Selection of removed nodes.
//
// For example if the selection s contains "<h1>", "<h2>" and "<h3>"
// and s.RemoveFiltered("h2") is called, only the "<h2>" node is removed
// (and returned), while "<h1>" and "<h3>" are kept in the document.
func ( *Selection) ( string) *Selection {
	return .RemoveMatcher(compileMatcher())
}

// RemoveMatcher removes from the current set of matched elements those that
// match the Matcher filter. It returns the Selection of removed nodes.
// See RemoveFiltered for additional information.
func ( *Selection) ( Matcher) *Selection {
	return .FilterMatcher().Remove()
}

// ReplaceWith replaces each element in the set of matched elements with the
// nodes matched by the given selector.
// It returns the removed elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( string) *Selection {
	return .ReplaceWithMatcher(compileMatcher())
}

// ReplaceWithMatcher replaces each element in the set of matched elements with
// the nodes matched by the given Matcher.
// It returns the removed elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( Matcher) *Selection {
	return .ReplaceWithNodes(.MatchAll(.document.rootNode)...)
}

// ReplaceWithSelection replaces each element in the set of matched elements with
// the nodes from the given Selection.
// It returns the removed elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( *Selection) *Selection {
	return .ReplaceWithNodes(.Nodes...)
}

// ReplaceWithHtml replaces each element in the set of matched elements with
// the parsed HTML.
// It returns the removed elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( string) *Selection {
	.eachNodeHtml(, true, func( *html.Node,  []*html.Node) {
		 := .NextSibling
		for ,  := range  {
			if .Parent != nil {
				.Parent.InsertBefore(, )
			}
		}
	})
	return .Remove()
}

// ReplaceWithNodes replaces each element in the set of matched elements with
// the given nodes.
// It returns the removed elements.
//
// This follows the same rules as Selection.Append.
func ( *Selection) ( ...*html.Node) *Selection {
	.AfterNodes(...)
	return .Remove()
}

// SetHtml sets the html content of each element in the selection to
// specified html string.
func ( *Selection) ( string) *Selection {
	for ,  := range .Nodes {
		for  := .FirstChild;  != nil;  = .FirstChild {
			.RemoveChild()
		}
	}
	return .eachNodeHtml(, false, func( *html.Node,  []*html.Node) {
		for ,  := range  {
			.AppendChild()
		}
	})
}

// SetText sets the content of each element in the selection to specified content.
// The provided text string is escaped.
func ( *Selection) ( string) *Selection {
	return .SetHtml(html.EscapeString())
}

// Unwrap removes the parents of the set of matched elements, leaving the matched
// elements (and their siblings, if any) in their place.
// It returns the original selection.
func ( *Selection) () *Selection {
	.Parent().Each(func( int,  *Selection) {
		// For some reason, jquery allows unwrap to remove the <head> element, so
		// allowing it here too. Same for <html>. Why it allows those elements to
		// be unwrapped while not allowing body is a mystery to me.
		if .Nodes[0].Data != "body" {
			.ReplaceWithSelection(.Contents())
		}
	})

	return 
}

// Wrap wraps each element in the set of matched elements inside the first
// element matched by the given selector. The matched child is cloned before
// being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( string) *Selection {
	return .WrapMatcher(compileMatcher())
}

// WrapMatcher wraps each element in the set of matched elements inside the
// first element matched by the given matcher. The matched child is cloned
// before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( Matcher) *Selection {
	return .wrapNodes(.MatchAll(.document.rootNode)...)
}

// WrapSelection wraps each element in the set of matched elements inside the
// first element in the given Selection. The element is cloned before being
// inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( *Selection) *Selection {
	return .wrapNodes(.Nodes...)
}

// WrapHtml wraps each element in the set of matched elements inside the inner-
// most child of the given HTML.
//
// It returns the original set of elements.
func ( *Selection) ( string) *Selection {
	 := make(map[string][]*html.Node)
	for ,  := range .Nodes {
		var  *html.Node
		if .Parent != nil {
			 = .Parent
		} else {
			 = &html.Node{Type: html.ElementNode}
		}
		,  := [nodeName()]
		if ! {
			 = parseHtmlWithContext(, )
			[nodeName()] = 
		}
		newSingleSelection(, .document).wrapAllNodes(cloneNodes()...)
	}
	return 
}

// WrapNode wraps each element in the set of matched elements inside the inner-
// most child of the given node. The given node is copied before being inserted
// into the document.
//
// It returns the original set of elements.
func ( *Selection) ( *html.Node) *Selection {
	return .wrapNodes()
}

func ( *Selection) ( ...*html.Node) *Selection {
	.Each(func( int,  *Selection) {
		.wrapAllNodes(...)
	})

	return 
}

// WrapAll wraps a single HTML structure, matched by the given selector, around
// all elements in the set of matched elements. The matched child is cloned
// before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( string) *Selection {
	return .WrapAllMatcher(compileMatcher())
}

// WrapAllMatcher wraps a single HTML structure, matched by the given Matcher,
// around all elements in the set of matched elements. The matched child is
// cloned before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( Matcher) *Selection {
	return .wrapAllNodes(.MatchAll(.document.rootNode)...)
}

// WrapAllSelection wraps a single HTML structure, the first node of the given
// Selection, around all elements in the set of matched elements. The matched
// child is cloned before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( *Selection) *Selection {
	return .wrapAllNodes(.Nodes...)
}

// WrapAllHtml wraps the given HTML structure around all elements in the set of
// matched elements. The matched child is cloned before being inserted into the
// document.
//
// It returns the original set of elements.
func ( *Selection) ( string) *Selection {
	var  *html.Node
	var  []*html.Node
	if len(.Nodes) > 0 {
		 = .Nodes[0]
		if .Parent != nil {
			 = parseHtmlWithContext(, )
		} else {
			 = parseHtml()
		}
	}
	return .wrapAllNodes(...)
}

func ( *Selection) ( ...*html.Node) *Selection {
	if len() > 0 {
		return .WrapAllNode([0])
	}
	return 
}

// WrapAllNode wraps the given node around the first element in the Selection,
// making all other nodes in the Selection children of the given node. The node
// is cloned before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( *html.Node) *Selection {
	if .Size() == 0 {
		return 
	}

	 := cloneNode()

	 := .Nodes[0]
	if .Parent != nil {
		.Parent.InsertBefore(, )
		.Parent.RemoveChild()
	}

	for  := getFirstChildEl();  != nil;  = getFirstChildEl() {
		 = 
	}

	newSingleSelection(, .document).AppendSelection()

	return 
}

// WrapInner wraps an HTML structure, matched by the given selector, around the
// content of element in the set of matched elements. The matched child is
// cloned before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( string) *Selection {
	return .WrapInnerMatcher(compileMatcher())
}

// WrapInnerMatcher wraps an HTML structure, matched by the given selector,
// around the content of element in the set of matched elements. The matched
// child is cloned before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( Matcher) *Selection {
	return .wrapInnerNodes(.MatchAll(.document.rootNode)...)
}

// WrapInnerSelection wraps an HTML structure, matched by the given selector,
// around the content of element in the set of matched elements. The matched
// child is cloned before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( *Selection) *Selection {
	return .wrapInnerNodes(.Nodes...)
}

// WrapInnerHtml wraps an HTML structure, matched by the given selector, around
// the content of element in the set of matched elements. The matched child is
// cloned before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( string) *Selection {
	 := make(map[string][]*html.Node)
	for ,  := range .Nodes {
		,  := [nodeName()]
		if ! {
			 = parseHtmlWithContext(, )
			[nodeName()] = 
		}
		newSingleSelection(, .document).wrapInnerNodes(cloneNodes()...)
	}
	return 
}

// WrapInnerNode wraps an HTML structure, matched by the given selector, around
// the content of element in the set of matched elements. The matched child is
// cloned before being inserted into the document.
//
// It returns the original set of elements.
func ( *Selection) ( *html.Node) *Selection {
	return .wrapInnerNodes()
}

func ( *Selection) ( ...*html.Node) *Selection {
	if len() == 0 {
		return 
	}

	.Each(func( int,  *Selection) {
		 := .Contents()

		if .Size() > 0 {
			.wrapAllNodes(...)
		} else {
			.AppendNodes(cloneNode([0]))
		}
	})

	return 
}

func parseHtml( string) []*html.Node {
	// Errors are only returned when the io.Reader returns any error besides
	// EOF, but strings.Reader never will
	,  := html.ParseFragment(strings.NewReader(), &html.Node{Type: html.ElementNode})
	if  != nil {
		panic("goquery: failed to parse HTML: " + .Error())
	}
	return 
}

func parseHtmlWithContext( string,  *html.Node) []*html.Node {
	// Errors are only returned when the io.Reader returns any error besides
	// EOF, but strings.Reader never will
	,  := html.ParseFragment(strings.NewReader(), )
	if  != nil {
		panic("goquery: failed to parse HTML: " + .Error())
	}
	return 
}

// Get the first child that is an ElementNode
func getFirstChildEl( *html.Node) *html.Node {
	 := .FirstChild
	for  != nil && .Type != html.ElementNode {
		 = .NextSibling
	}
	return 
}

// Deep copy a slice of nodes.
func cloneNodes( []*html.Node) []*html.Node {
	 := make([]*html.Node, 0, len())

	for ,  := range  {
		 = append(, cloneNode())
	}

	return 
}

// Deep copy a node. The new node has clones of all the original node's
// children but none of its parents or siblings.
func cloneNode( *html.Node) *html.Node {
	 := &html.Node{
		Type:     .Type,
		DataAtom: .DataAtom,
		Data:     .Data,
		Attr:     make([]html.Attribute, len(.Attr)),
	}

	copy(.Attr, .Attr)
	for  := .FirstChild;  != nil;  = .NextSibling {
		.AppendChild(())
	}

	return 
}

func ( *Selection) ( []*html.Node,  bool,
	 func( *html.Node,  *html.Node)) *Selection {

	 := .Size() - 1

	// net.Html doesn't provide document fragments for insertion, so to get
	// things in the correct order with After() and Prepend(), the callback
	// needs to be called on the reverse of the nodes.
	if  {
		for ,  := 0, len()-1;  < ; ,  = +1, -1 {
			[], [] = [], []
		}
	}

	for ,  := range .Nodes {
		for ,  := range  {
			if  !=  {
				(, cloneNode())
			} else {
				if .Parent != nil {
					.Parent.RemoveChild()
				}
				(, )
			}
		}
	}

	return 
}

// eachNodeHtml parses the given html string and inserts the resulting nodes in the dom with the mergeFn.
// The parsed nodes are inserted for each element of the selection.
// isParent can be used to indicate that the elements of the selection should be treated as the parent for the parsed html.
// A cache is used to avoid parsing the html multiple times should the elements of the selection result in the same context.
func ( *Selection) ( string,  bool,  func( *html.Node,  []*html.Node)) *Selection {
	// cache to avoid parsing the html for the same context multiple times
	 := make(map[string][]*html.Node)
	var  *html.Node
	for ,  := range .Nodes {
		if  {
			 = .Parent
		} else {
			if .Type != html.ElementNode {
				continue
			}
			 = 
		}
		if  != nil {
			,  := [nodeName()]
			if ! {
				 = parseHtmlWithContext(, )
				[nodeName()] = 
			}
			(, cloneNodes())
		}
	}
	return 
}